Le langage XSL

Dernière mise à jour : 27/06/2004
[ Version imprimable ]
Introduction
Présentation
Le minimum vital.
  • Un tigre dans le moteur.
  • XmlSpy : l'espion qui aimait XML...
  • Les 3 règles par défaut.
  • XPath : le SQL pour XML.
La règle est de rigueur.
  • Paramètre et variable constants...
  • La règle par deux.
  • Peu importe si on inclut.
  • La priorité est de mode.
XSL pour les pro.
  • EXSL, aux frontières du standard...
  • XSLTUnit : quand XSL se teste unitairement lui-même.
Ressources.
  • Sites.
  • Livres.
Conclusion.
  • Acte I : Quelques règles s'imposent...
  • Acte II : Et moi qui ne voulais pas dupliquer.
  • Acte III : Système de gestion de contenu ou de contenant ?


Introduction

[ HAUT DE PAGE ]

Lorsque j'ai abordé XSL (eXtensible Stylesheet Language) pour la première fois, la majorité des ressources ne faisaient que lister de manière exhaustive les fonctions du langage. Il n'y avait pas d'autres solutions que de se "palucher" les quelques 99.10^99 fonctions, pour déceler celle qui pouvait répondre au mieux à mon problème parmi toutes celles potentiellement intéressantes.

Ce qui m'a manqué, c'est une vue d'ensemble des fonctionnalités (plus que des fonctions), et des conseils sur quelle solution mettre en place pour un problème donné.

Je vais donc essayer dans cet article de présenter les diverses techniques qu'offre XSL, au travers des réponses que j'ai pu trouver, mais aussi mon avis dans la mesure du possible, voire quelques indices ou astuces. Cela afin d’orienter au mieux les développements, et donc de mieux maîtriser la conception... Pour répondre à ces objectifs, je vais tout d’abord présenter XSL, en introduisant les mots clefs, pour ensuite aborder les outils et principes nécessaires à la réalisation de transformations XSL.

Ca me permettra de poursuivre sur des éléments permettant d’envisager des développements complexes avec sérénité, et de conclure en 3 actes, sur « les tenants et les aboutissants » (copyright SuperJemmi) du langage, les problématiques qu’il induit, et des intégrations potentielles dans des solutions d’envergure.

Quel programme !

Avant de continuer, je tiens à remercier mon « comité de relecture », à savoir Bobo, Cyp et Den’z.



Présentation

[ HAUT DE PAGE ]

XSLT est donc un langage permettant d'extraire et de restructurer des informations, à partir d'un document XML, et souvent vers un autre document XML. Le langage de transformation XSLT fait l'objet d'une recommandation du W3C.

Pour rappel, un document XML (eXtensible Markup Language) est un fichier texte contenant des balises, un peu comme un fichier HTML, avec certaines spécificités :

Sachant cela, un document XML peut donc également être représenté sous la forme d'un arbre, où les embranchements, ou nœuds, sont les balises XML. La représentation sous forme textuelle est privilégiée dans un contexte de communication, de gestion de flux, alors que celle de l'arbre est plus commode dans un contexte de traitement, comme c'est le cas ici. On peut alors voir XSL comme un moyen de transformer cet arbre initial, en un autre arbre.... ou en un simple tas de feuilles ! En effet, le document résultat d'une transformation XSL peut être un autre document :

Enfin, si j'ai rappelé ces règles, c'est qu'une transformation XSLT se définie dans un fichier texte en utilisant le langage XSL qui est lui-même du XML, et suit donc les mêmes règles. Ce qui implique qu'il pourra être modifié lui-même par une feuille XSL, ou encore qu'il pourra être modifié par programmation avec tout langage possédant une interface DOM.

Avant de continuer, j'aimerais apporter une précision pour lever toute ambiguïté. On entend souvent parler, et on mélange parfois, les acronymes XSL, XSLT et XSL-FO.



Le minimum vital.

[ HAUT DE PAGE ]

Le but ici est de présenter les fonctionnalités XSL de base permettant d'écrire et de mettre en oeuvre des transformations simples, à partir d'un document XML.

Un tigre dans le moteur.

Afin de donner vie à ce fichier texte, inerte, on doit utiliser un moteur, un processeur XSLT, auquel on fournit le fichier XML d'entrée, le document XSL qui spécifie les transformations à apporter, et éventuellement le nom du fichier à générer.

Un descriptif, voir un comparatif des processeurs XSLT disponibles pouvant à lui seul faire l'objet d'un article, je ne vais citer que les trois que j'ai utilisés, à savoir :

L'avantage de ce dernier, est qu'il est livré en standard avec Windows, et intégré à Internet Explorer. Le résultat est qu'il suffit d'indiquer le chemin d'accès au document XSLT (<?xml-stylesheet type="text/xsl" href="MA_TRANSFORMATION.XSL"?> [1]) en début du fichier XML, puis d'ouvrir ce dernier avec IE pour visualiser directement le résultat de la transformation, sans autres outil, installation ou manipulation particulière.

Exemple de fichier XML :

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="MA_TRANSFORMATION.XSL"?> <!-- [1] -->
<document>
   <title>XSL</title>
   <chapter>
      <title>Introduction</title>
      <para>Bla bla bla...</para>
   </chapter>
</document>

XmlSpy : l'espion qui aimait XML...

Quel que soit le langage, tout développeur a souvent un IDE de prédilection. Pour ma part, pour travailler sur XML-XSL, j'ai utilisé XmlSpy 2004 de la société Altova qui fournit divers outils pour travailler sur XML.

Interface graphique de XmlSpy

Il s'agit d'un IDE orienté XML, et ses technologies connexes (HTML, DTD-Schema, XSL...), aux fonctionnalités diverses et variées...

Pour les fonctionnalités XSL, XmlSpy permet notamment

Seule ombre au tableau : il vous faudra disposer d'une importante résolution d'écran, comme pour tout IDE multi-fenêtres. Mais cela est d'autant plus vrai que le langage considéré (XML) est ici très verbeux (oubliez la sacro-sainte "ligne de 80 caractères"). De plus, par défaut, le mode debug s'ouvre avec 3 fenêtres en mosaïque : le document XML d'entrée, le XSL de transformation et le HTML de sortie. Il faudra également prévoir une machine puissante pour subvenir aux besoins que nécessite le traitement d'un langage verbeux (décidément).

Autre point important : les tarifs. XmlSpy existe en trois éditions :

  1. une "Home Edition", gratuite depuis la version 2004, mais déjà très utile,
  2. une "Professional Edition" (qui permet notamment de debugger en XSLT) à 400 euros la licence, et
  3. une "Enterprise Edition" à 800 euros la licence.
Pour un liste détaillée et comparée des fonctionnalités, reportez vous à la matrice disponible sur leur site, pratique et bien faite.

En conclusion, XmlSpy dans sa version gratuite est un bon outil si l'on souhaite éditer des fichiers XML, mais doit laisser place à une des versions payantes si l'on souhaite disposer d'une solution pertinente et efficace pour travailler sur un ensemble de technologies XML, que se soit l'ensemble du processus de transformation XSL (et notamment le debugger XSL), voire en environnement distribué ou via une base de données.

Les 3 règles par défaut.

Tout d'abord, il faut avoir conscience des trois règles par défaut qui, soit vous permettront avec un fichier XSL vide d'extraire l'intégralité du texte d'un fichier document XML, soit vous amèneront à rencontrer des situations inattendues si vous n'y prenez pas garde.

En effet, XSL définit un trio de règles qui sont appliquées quand aucune des règles que vous avez écrites n'est sélectionnée, et donc à fortiori lorsque le fichier XSL est vide.

Fichier XSL minimal (vide) :

<?xml version="1.0" encoding="UTF-8"?>
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>

Fichier XSL équivalent (règles par défaut) :

<?xml version="1.0" encoding="UTF-8"?>
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <!-- [1] -->
   <xsl:template match="/ | *">
      <xsl:apply-templates/>
   </xsl:template>

   <!-- [2] -->
   <xsl:template match="text() | @*">
      <xsl:value-of select="."/>
   </xsl:template>

   <!-- [3] -->
   <xsl:template match="processing-instruction() | comment()"/>

</xsl:stylesheet>

La première règle par défaut [1], s'applique au nœud racine et à tout autre nœud : elle déclenche un appel de règle dessus. La second [2], s'applique à tout nœud de type texte (à tout contenu textuel) et à tous les attributs de nœud : elle affiche alors leur valeur. La troisième et dernière règle par défaut [3], s'applique aux instructions de traitement et aux commentaires, pour lesquels elle ne fait rien.

Une des principales conséquences de ces règles, est de penser à inhiber toute balise que l'on ne souhaite pas voir afficher, soit parce que l'on ne souhaite pas la voir dans le document généré, soit parce qu'elle est gérée dans une autre règle...

Ainsi, si l'on souhaite interdire l'affichage d'une balise <copyright>, qui est traitée par ailleurs, il faudra penser à l'inhiber de la sorte :

<xsl:template match="copyright"/>
Mais nous y reviendrons...

XPath : le SQL pour XML.

L'observation de ces règles nous permet d'entrevoir le rôle et l'intérêt de XPath.

En une phrase, XPath est à XML ce que SQL est aux bases de données, à savoir un langage pour écrire des requêtes, mais uniquement de recherche en ce qui concerne XML. Tout comme XSLT, XPath fait l'objet d'une spécification, distincte, du W3C.

Une expression XPath, encore appelée chemin de localisation XPath, est constituée d'une ou plusieurs étapes de localisation XPath, séparées entre elles par le symbole '/'. Chacune de ces étapes de localisation pouvant elle-même être constituée dans l'ordre :

  1. un axe (par défaut l'axe implicite est child), qui permet d'indiquer si l'on remonte vers les parents, ou si l'on s'enfonce vers les enfant, suivi du séparateur ::, suivi de
  2. un test de nœud, qui spécifie un nœud ou un ensemble de nœuds (test portant sur un d'élément, d'attribut, de namespace ou sur un joker), suivi de
  3. zéro à n prédicats, encadrés chacun par [ ], qui ajoutent des restrictions supplémentaires aux chemins.

Le langage XPath peut être utilisé dans sa forme développée ('parent' pour remonter au nœud père), ou abrégée ('..' toujours pour remonter au nœud père). Dans sa forme abrégée, une expression XPath ressemble alors au chemin, au 'path', d'un fichier sur le disque dur de l'ordinateur.

Si l'on représente un document XML et ses balises entrelacées comme un arbre de dépendances, une expression XPath est une énigme pour laquelle l'enquêteur (le processeur XSLT) peut trouver des solutions diverses en qualité et en quantité, mais qui correspondent tout à fait aux indices qu'il a à sa disposition. L'évaluation de l'expression (résolution de l'énigme) peut donner comme résultat, soit une valeur (numérique ou alphanumérique), soit un sous-ensemble des nœuds de l'arbre.

On peut utiliser une expression XPath à divers endroits du code XSL :

  1. Désignation des nœuds auxquels s'applique une règle (comme ci-dessus, pour les règles par défaut) : <xsl:templates select="FILM/TITRE"/>...<xsl:templates> pour définir une règle qui s'applique à toute balise TITRE, fille d'une balise FILM, elle-même fille de la balise sur laquelle on travaille,
  2. Sélection de nœuds auxquels on souhaite appliquer une règle : <xsl:apply-templates select="//CINEMA[VILLE='Montgeron']/SALLE"/> pour propager l'appel de règle à toute balise SALLE fille d'une balise CINEMA dont la balise fille VILLE vaut 'Montgeron', quel que soit l'endroit où se trouve cette balise CINEMA dans le document XML,
  3. Extraction des valeurs : <xsl:value-of select="../SALLE/@NO"/> pour obtenir la valeur de l'attribut NO de toute balise SALLE qui se trouve au même niveau que la balise sur laquelle on travaille,
  4. Prédicats de test : <xsl:if test="$titre='' and TITRE=$titre">...<xsl:if> pour effectuer un traitement que lorsque l'on a une balise TITRE, fille de la balise sur laquelle on travaille, égale au paramètre titre que l'on a et qui ne doit pas être une chaîne vide.

Enfin, pour maîtriser les expressions XPath, il est important de bien distinguer le nœud courant du nœud contextuel. Le nœud courant est celui dans lequel on est quand on commence à lire l'expression XPath, celui qui est à l'origine de cette expression. Le nœud contextuel quant à lui, est la cible, le ou les nœuds résultats successifs.

Pour plus de détails, et notamment la liste exhaustive des symboles et des spécificateurs d'axe, vous pouvez vous reporter au paragraphe intitulé "chemin de localisation ou motifs XPath" du tutoriel Comprendre XSLT.



La règle est de rigueur.

[ HAUT DE PAGE ]

Paramètre et variable constants...

Lorsque j'ai approché XSL, je suis tombé sur deux notions que j'ai eues du mal à distinguer : xsl:variable et xsl:param.

Tout d'abord, pour être clair, comme son nom de l'indique pas, une variable est... constante, tout comme les paramètres. Une fois instanciée dans une règle, éventuellement à la racine, sa valeur ne peut être modifiée, et on ne peut définir une autre variable portant le même nom dans la même portée. Pour définir une variable qui contiendrait le nom du CINEMA de la ville de Montgeron :

<xsl:variable name="nomCinema" select="CINEMA[VILLE='Montgeron']/NOM"/>
. Dans le cas où la valeur de la variable devrait être un peu plus élaborée, comme le reformatage du nom du cinéma, pour par exemple mettre l'article éventuel à la fin entre parenthèses, on peut définir la valeur de la variable en appelant une fonction ainsi :
<xsl:variable name="nomCinema"><xsl:call-template name="formateNomCinema"/></xsl:variable>
.

Dans tous les cas, l'appel à une variable s'effectue de la sorte :

Mon cinéma préféré est le <xsl:value-of select="$nomCinema"/> car l'ambiance y est...
.

Par extension (abusive ?), tout ce qui vient d'être dit pour une variable fonctionne avec un paramètre : le code ci-dessus conservera le même comportement si l'on remplace xsl:variable par xsl:param.

Par contre, les paramètres ont deux autres utilisations où ils sont irremplaçables.

La première est le passage de paramètres à la feuille XSL lors de l'appel au processeur, afin de disposer dans le XSL d'informations inaccessibles pendant la transformation, amis disponibles dans l'environnement d'appel (ligne de commande, programme...). Très pratique si l'on veut faire apparaître dans le document généré, le login de celui qui l'a généré, ou encore la date de la transformation, la date courante n'étant pas accessible en XSL standard. Pour cela, il suffit de :

  1. définir au début du document XSL le paramètre, avec un nom, et éventuellement une valeur par défaut,
  2. et d'indiquer le nom et la valeur du paramètre lors de l'appel au processeur XSL (si cette étape est omise, volontairement ou non, le paramètre prendra alors la valeur par défaut dans le document XSL).
Cet appel étant propre à chaque processeur, je vous indique en exemple l'appel au processeur Xalan-J, et vous laisse vous reporter à la documentation de votre propre processeur XSL.

Exemple d'appel en ligne de commande avec la date courante en paramètre
java org.apache.xalan.xslt.Process -IN foo.xml -XSL foo.xsl -OUT foo.out -PARAM buildDate %DATE%
					
Instruction XSL pour récupérer cette date dans la transformation
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="buildDate">INCONNUE</xsl:param>

    <!-- ... -->
</xsl:stylesheet>

L'autre utilisation, est le passage de paramètre à une règle cette fois...

La règle par deux.

XSL repose sur la notion de règle, et pour définir une règle, deux possibilités s'offrent à nous, chacune traduisant 2 façons radicalement différentes de penser.

La première, est de nommer la règle, de lui associer éventuellement des paramètres, et ensuite de l'appeler par son petit nom. Cette programmation, traditionnellement fonctionnelle, permet de se décrocher de l'arborescence du fichier XML d'entrée, pour imposer sa propre séquence d'appels, ou de créer des règles 'outils' qui permettent de factoriser des traitements récurrents. Tout comme les paramètres passés au processeur, l'utilisation d'un paramètre dans une règle nommée, suit les règles suivantes :

Prenons l'exemple d'une règle toUpper qui permettrait d'afficher une chaîne de caractères en majuscule, et qui serait utiliser pour une autre règle displayTitleInUpperCase, pour afficher le titre en majuscules.
Règle nommée et ses paramètres.
<!-- Definition de la regle 'toUpper' -->
<xsl:template name="toUpper">
   <xsl:param name="string"/> <!-- Definition du parametre 'string' -->
   <xsl:value-of select="translate($string, 'abcdefghijklmnopqrstuvwyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
</xsl:template>

<xsl:template name="displayTitleInUpperCase">
   <!-- Appel a la regle 'toUpper' -->
   <xsl:call-template name="toUpper">
      <xsl:with-param name="string" select="MOVIE/TITLE"/> <!-- Appel au parametre 'string' -->
   </xsl:call-template>
</xsl:template>

L'autre façon de faire, est de définir la règle en indiquant la balise déclenchante. Pour comprendre cette programmation déclarative, orientée pattern matching, il faut se rappeler qu'une transformation XSL s'opère à mesure que l'on parcourt l'arbre d'entrée. Ainsi, à mesure qu'il parcourt les nœuds, le processeur XSL regarde si une règle est associée à la balise en cours, et la déclenche si c'est le cas. Ce mécanisme, exposé dans le chapitre sur XPath, est celui utilisé dans les règles par défaut. Nous verrons plus tard le cas où plusieurs règles correspondent la balise en cours...

L'inconvénient des règles nommées, est qu'il est impossible de "surcharger" une règle nommée : on ne peut pas définir deux règles avec un nom identique... Si le besoin s'en fait ressentir, on peut toujours jouer avec les paramètres... ou peut-être concevoir différemment, sachant qu'il est possible, avec le pattern-matching, d'associer plusieurs règles à une même balise, mais comme je viens de le dire, nous verrons cela après...

Pour illustrer ce paragraphe, prenons l'exemple du 'copyright'. Imaginons que nous avons une balise copyright dans notre fichier XML d'entrée. Il est à peu près évident pour tout le monde, que ce copyright serait bien avisé de s'afficher en bas du document généré, quel que soit l'endroit où apparaît la balise dans le document XML d'entrée. Une façon de faire serait de :

Exemple de programmation à la fois déclarative et fonctionnelle.
<!-- [1] -->
<xsl:template select="copyright"/>

<!-- [2] -->
<xsl:template name="displayCopyright">
   <xsl:value-of select="\\copyright"/> (c) <xsl:value-of select="\\copyright\year"/>
</xsl:template>

<xsl:template match="/">
   <html>
      <head>
         <title>Titre de la page</title>
      </head>
      <body>
         <!-- [...] -->
         <xsl:apply-templates/>
         <!-- [...] -->
         <xsl:call-template name="displayCopyright"/> <!-- [3] -->
      </body>
   </html>
</xsl:template>

Peu importe si on inclut.

En XSL on peut pousser à l'extrême la notion de programme principal utilisant des librairies. Étant donné que les fichiers XSL sont au format texte, cette notion de dépendance peut s'exprimer que par des mots clefs, deux en l'occurrence : xsl:include et xsl:import .

L'utilisation de include revient à prendre le fichier inclus, et à "l'inclure", le copier à l'endroit où le mot clef est utilisé. On peut donc utiliser cette instruction n'importe où ([1]) dans le fichier principal. Mais doit-on l'autoriser ?...

Utilisation de l'instruction xsl:include.
<xsl:template match="/">
   <html>
      <head>
         <title>Titre de la page</title>
      </head>
      <body>
         <!-- [...] -->
         <xsl:apply-templates/>
         <!-- [...] -->
         <xsl:call-template name="displayCopyright"/>
      </body>
   </html>
</xsl:template>

<xsl:include href="copyrightLibrairy.xsl"/> <!-- [1] -->
					

A l'inverse, le mot clef import doit être présent au début du fichier, avant toute autre instruction.

Utilisation de l'instruction xsl:import.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:import href="commonLibrairy.xsl"/> <!-- [1] -->

    <!-- ... -->
</xsl:stylesheet>
					

Dans le cas d'une variable, définie dans un fichier dépendant, l'utilisation de xsl:include permet d'accéder à cette variable, puisqu'elle est considérée comme étant dans le même fichier. Dans ce cas, il est donc notamment impossible de définir deux variables avec le même nom (une dans chaque fichier). A l'inverse, l'utilisation de xsl:import rend la variable inaccessible dans le fichier principal, puisqu'elle est considérée comme étant dans une portée inférieure. Cela rend donc possible la "re-définition" d'une variable avec le même nom, sachant qu'il y aura en fait masquage.

Dans le cas de dépendances en losange (agenda.xsl dépendant de mois.xsl et de rdv.xsl, ces deux derniers dépendants eux même d'un même fichier jour.xsl), l'utilisation de xsl:import est très souvent la seule échappatoire.

Importance de l'import dans un diagramme de dépendances en losange.
              +-->  mois.xsl --+
              |                |
agenda.xsl  --+                +-->  jour.xsl
              |                |
              +-->  rdv.xsl  --+
En effet, si on veut définir des règles par leur nom (et non pas par un motif), l'utilisation d'un include génère une "redéfinition" au niveau du transformateur XSLT lorsqu'il analyse le fichier doublement inclus (jour.xsl) pour la seconde fois.

Attardons-nous un peu sur l'import et ses subtilités, à savoir la notion de préséance. Si l'on schématise les dépendances d'import par un arbre, alors la préséance diminue à mesure que l'on parcourt l'arbre en profondeur d'abord, puis de droite à gauche. Or c'est la règle ayant la préséance la plus élevée qui est d'abord sélectionnée (puis la notion de priorité est appliquée...).

On peut donc voir ce mécanisme d'import comme analogue à celui de la surcharge en Programmation Orientée Objet.

Mais comment alors appeler la règle surchargée ?... xsl:apply-imports . Cela peut s'avérer très utile dans le cas où il existerait un traitement par défaut pour certaines balises dans une feuille XSL commune, et que l'on souhaite pour des balises données, ajouter des traitements supplémentaires, tout en conservant les traitements par défaut. Il suffit alors d'importer dans notre feuille XSL la feuille commune [1], de définir une règle pour la balise concernée [2], d'y définir nos traitement, et d'ajouter xsl:apply-imports [3] là où les traitements par défaut doivent être présentés.

Utilisation de xsl:apply-imports.
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:import href="personne.xsl"/> <!-- [1] -->
   <xsl:output method="html" indent="yes"/>

   <xsl:template match="PERSONNE"> <!-- [2] -->
      <xsl:apply-imports/> <!-- [3] -->
      <b>Poste</b> : <xsl:value-of select="POSTE"/><br/>
      <b>Salaire</b> : <xsl:value-of select="SALAIRE"/><br/>
   </xsl:template>

   <!-- ... -->
</xsl:stylesheet>

La priorité est de mode.

Que se soit dans la programmation déclarative ou la programmation fonctionnelle, l'ordre de définition des règles au sein d'une même feuille est sans effet sur le choix de règle du processeur. De plus, il peut arriver que pour une balise donnée, un motif donné, le processeur retiennent dans un premier temps plusieurs règles, qui entrent donc en conflit, dans un premier seulement, car le processeur ne retiendra toujours au final qu'une seule règle maximum.

Dans le cas déclaratif, où les règles sont définies par un motif et non par un leur nom, il est cependant possible d'influencer le processeur XSL dans ses choix de règles à sélectionner. La corruption est doublement possible, soit par la notion de priorité, soit par celle de mode.

Commençons par la plus simple, la priorité. Cette ruse de sioux n'a de sens que dans le cas où l'on définit des règles avec différents motifs, différentes expressions XPath, qui peuvent potentiellement correspondre à une même balise. Pour maîtriser le déclenchement des règles il suffit alors d'instancier l'attribut priority avec une valeur d'autant plus élevée que l'on souhaite la rendre prioritaire.

Prenons l'exemple de l'arbre XML d'une société, où les nœuds sont les salariés, avec les balises <INGENIEUR>, <STAGIAIRE>, <COMMERCIAL>, <DIRECTION> et <ADMINISTRATIF>. Imaginons que suite à l'achat d'une machine à café, nous n'ayons plus besoin de stagiaires, et que nous souhaitions donc obtenir un nouvel arbre XML, filtré de tout stagiaire. On peut alors définir une règle générique [1], associée à toute balise (match="node()"), avec une faible priorité, qui duplique le nœud courant, et une autre, associée au stagiaire [2], de forte priorité, qui ne fait rien (comme les stagiaires ;o).

Notion de priorité dans les règles.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:template match="/"><xsl:apply-templates/></xsl:template>

   <!-- [1] -->
   <xsl:template match="node()" priority="-1">
      <xsl:copy/>
   </xsl:template>

   <!-- [2] -->
   <xsl:template match="STAGIAIRE" priority="10"/>

</xsl:stylesheet>

La seconde arme est la notion de mode. A son sujet, il faut savoir :

Ainsi, si une règle est définie avec un mode quelconque, elle ne pourra pas être déclenchée si le même mode n'est pas spécifié à l'appel.

De plus, si dans une règle définie avec un mode "monMode", il y a des appels à d'autres règles sans mode spécifié explicitement, dans ce cas c'est le mode "monMode" qui sera implicitement appliqué. Un exemple classique ici, est la génération d'une table des matières en début d'article, à partir du contenu XML de l'article.

L'article que vous lisez a été écrit en XML, en respectant la DTD DocBook. Il est donc constitué d'une balise racine <article> qui contient notamment des balises <chapter>, chacun de ces chapitres contenant une balise <title> et des balises <para> (qui elles contiennent le texte, le contenu des paragraphes). Il ne reste plus qu'a écrire deux règles pour le motif <chapter>, une avec l'attribut mode valant par exemple tableOfContent [1], qui ne fait qu'afficher le titre du chapitre, et une deuxième règle [2], qui elle permet d'afficher un chapitre dans son ensemble (titres, contenu...). Ensuite, on appelle ces deux règles, dans cet ordre [3] et [4], à la racine du document, pour chacun des chapitres.

Pour information, l'utilisation de la fonction XSL generate-id(node), génère comme son nom l'indique, un identifiant unique pour tout nœud, et donc notamment les titres de chapitre, et permet ainsi de mettre en place des liens croisés au sein d'un document HTML généré, entre le titre dans la table des matières, et le titre dans le corps de l'article.

Utilisation de la propriété mode des règles pour générer une table des matières.
<!-- ... -->

<xsl:template match="/">
   <html>
      <head><title>Titre de la page</title><head>
      <body>
         Table des matières<br/>
         <!-- [3] -->
         <xsl:apply-templates select="chapter" mode="tableOfContent"/>
         <!-- [...] -->
         <!-- [4] -->
         <xsl:apply-templates select="chapter"/>
         <!-- [...] -->
      </body>
   </html>
</xsl:template>


<!-- [1] -->
<xsl:template match="chapter" mode="tableOfContent">
   <a>
      <xsl:attribute name="href">#<xsl:value-of select="generate-id(.)"/></xsl:attribute>
      <xsl:value-of select="title"/>
   </a>
</xsl:template>

<!-- [2] -->
<xsl:template match="chapter">
   <a><xsl:attribute name="name"><xsl:value-of select="generate-id(.)"/></xsl:attribute></a>
   <h2><xsl:value-of select="title"/></h2>
   <xsl:apply-templates/>
</xsl:template>

<!-- ... -->



XSL pour les pro.

[ HAUT DE PAGE ]

EXSL, aux frontières du standard...

EXSL, pour Extended XSL, est comme son nom l'indique, un mécanisme permettant d'étendre XSL lorsque ce dernier ne répond plus à nos besoins.

Les extensions XSL sont de deux types :

La première catégorie est assurément la moins portable. Quant à la seconde, la portabilité est directement liée au choix du langage. Même en prenant un langage apparemment portable (qui ne pense pas à Java ?), nous n'avons aucune garantie, car concernant les extensions il y a :

De plus, on peut dire que la notion d'extension est "doublement" liée au processeur utilisé :

Ainsi, pour décrire brièvement ces mécanismes, sur les trois processeurs que j'ai énumérés en début d'article, le "O'Reilly - XSLT en action" a besoin d'une vingtaine de pages. Pour plus de précisions, je vous laisse donc vous y référer, et vous indique également les adresses qu'il cite : présentation des extensions sur Xalan-J ainsi que liste des extensions disponibles sur Xalan-J,

Tout ceci pour dire que devant ces combinaisons, il apparaît clair que la portabilité n'est vraiment pas acquise.

Si vous décidez cependant, ou devez, utiliser EXSL, il faut avoir à l'esprit qu'un nombre important d'extensions est déjà implémenté. Pour en avoir un aperçu, vous pouvez visiter le site web EXSLT.org. Sachant qu'une partie d'entre elles (celles écrites en XSL) peut être intégrée, par simple copier-coller, comme n'importe quelle autre règle développée par vos soins, il peut être judicieux de chercher un peu avant de réinventer la roue. Je pense par exemple à la gestion des dates...

Par définition, EXSL se veut à la limite du standard XSL, ce qui réduit forcément sa portabilité.

L'utilisation des fonctions EXSLT ne garantit pas la portabilité, puisqu'actuellement aucune mise en oeuvre ne les inclut toutes. En outre, d'après le site web d'EXSLT, certaines fonctions n'ont pas encore d'implémentation. L'équipe EXSLT compense cela en fournissant des versions en XSLT, en JavaScript et/ou en MSXML lorsque c'est possible.

La meilleure raison d'utiliser EXSLT est que les membres de l'équipe EXSLT sont très actifs dans la communauté XSLT, et que la plupart des processeurs offriront ces extensions tôt ou tard. Il est aussi possible qu'une partie de leur travail soit incorporé dans des versions ultérieures du standard XSLT.

Reprenons l'exemple de la date. La gestion des dates et de l'heure (conversions, format d'affichage, opérations, unités...) n'est pas disponible dans XSL. Le premier réflexe pourrait donc être de se tourner vers EXSLT, qui fournit les fonctions nécessaires... Mais on peut aussi soit ré-écrire les quelques fonctions nécessaires, soit retrouver l'implémentation XSL de ses fonctions si elles sont utilisées en nombre, pour les intégrer au code XSL existant. Mais pour obtenir la date courante, chose possible avec EXSL, comment faire alors en XSL ?... Et bien on peut la passer (la date) en paramètre au processeur XSL au moment de l'appel à ce dernier ! On utilise ainsi le mécanisme le mécanisme de passage de paramètres au processeur XSL (vu plus haut), qui lui est en standard sur XSL.

Cela pour conclure sur le fait qu'on ne peut pas répondre à tous les besoins de transformation XML seulement avec XSL. Mais les exceptions sont rares et propres à des cas isolés, comme la décompression du flux d'entrée, ou le besoin d'établir un index sur plusieurs documents, donc plusieurs transformations successives. Ainsi, avec une bonne maîtrise et un peu d'effort, il est tout à fait possible, dans la majorité des cas, de respecter le standard et donc d'assurer la portabilité. J'encouragerais donc à considérer EXSLT plutôt comme une source d'inspiration, que comme un véritable outil. Car je pense qu'une utilisation excessive d'EXSLT dans une transformation XSL, remet en cause la pertinence même du choix d'XSL pour accomplir la transformation, face à des traitements purement et entièrement logiciels...

XSLTUnit : quand XSL se teste unitairement lui-même.

XSLTUnit est un framework de tests unitaires pour les transformations XSLT, comme les harnais X-Unit existant pour d'autres langages (Java, C++...).

Le père de ce harnais de tests n'est autre que le webmaster du site XmlFr.org, j'ai nommé Eric van der Vlist.

La mise en place d'une batterie de tests unitaires (nommée par exemple libraryTest.xsl) sur une transformation XSLT (nommée library.xsl) avec XSLTUnit implique de :

  1. créer la feuille XSLT de test (libraryTest.xsl),
  2. y importer la feuille XSLT à tester (library.xsl),
  3. et la feuille XSLT contenant la définition des règles XSLTUnit (xsltunit.xsl) que l'on y utilise,
  4. puis d'appliquer cette feuille de test (libraryTest.xsl) à un fichier XML (library.xml), qui serait normalement transformé par la feuille XSLT à tester,
  5. pour obtenir le résultat sous forme XML (libraryTestResult.xml).
Fichiers à considérer pour un tests XSLTUnit.
							

    library.xml

        ||                            +--> xsltunit.xsl
        ||                            |
        ||  libraryTest.xsl --import--+
       \||/                           |
        \/                            +--> library.xsl

libraryTestResult.xml
						

Cette feuille XSLT de test, contient un ensemble de tests, chacun d'entre eux est un appel à l'une des règles fournies par XSLTUnit. Par exemple, la règle xsltu:assertEqual se définit avec les en paramètres suivants :

  1. un nom pour le test ('full-value'),
  2. le nœud XML sur lequel on travaille (document('library.xml')/library/book[isbn='0836217462']/title)
  3. et le résultat attendu (<h1>Being a Dog Is a Full-Time Job</h1>).
Exemple de fichier de test utilisant XSLTUnit.
<xsltu:test id="test-title">
   <xsl:call-template name="xsltu:assertEqual">
      <xsl:with-param name="id" select="'full-value'"/>
      <xsl:with-param name="nodes1">
         <xsl:apply-templates select="document('library.xml')/library/book[isbn='0836217462']/title"/>
      </xsl:with-param>
      <xsl:with-param name="nodes2">
         <h1>Being a Dog Is a Full-Time Job</h1>
      </xsl:with-param>
   </xsl:call-template>
</xsltu:test>

Le résultat de ces tests, de cette transformation XSLT, est un fichier XML contenant des balises xsltu:test.

Exemple de fichier résultat d'un test XSLTUnit.
<!-- SUCCES -->
<xsltu:test id="test-title-content">
   <xsltu:assert id="content-value" outcome="passed"/>
</xsltu:test>

<!-- ECHEC -->
<xsltu:test id="test-title">
   <xsltu:assert id="full-value" outcome="failed">
      <xsltu:message>
         <xsltu:diff name="">
            <xsltu:diff name="h1">
               <xsltu:no-match>
                  <xsltu:node>Being a Dog Is a Full-Time Job!</xsltu:node>
                  <xsltu:node>Being a Dog Is a Full-Time Job</xsltu:node>
               </xsltu:no-match>
            </xsltu:diff>
         </xsltu:diff>
      </xsltu:message>
   </xsltu:assert>
</xsltu:test>



Ressources.

[ HAUT DE PAGE ]

Sites.

Livres.



Conclusion.

[ HAUT DE PAGE ]

Acte I : Quelques règles s'imposent...

Étant donné que je n'ai pas retrouvé, ni dans la littérature, ni dans les sites, les derniers thèmes que je vais aborder, je tends à penser qu'il s font partis de ma conclusion, conclusions qui va donc commencer par ici...

Le premier point concerne ce que j'appellerais l'ouverture du langage.

En effet, il apparaît avec un peu de recule, que XSL permet de coder de diverses manières.

La première impression qui frappe quand on découvre XSL n'est-elle pas la consternation pour les plus combatifs, et la déroute pour les autres ?

Cela tient, à mon sens, tant à la différence, qu'à la diversité, des façons de penser et donc de coder qu'implique XSL par rapport à des langages de programmation plus traditionnellement fonctionnels ou objets. Je pense en premier lieu au pattern-matching, mais aussi à tout ce que cela implique, comme par exemple la notion de priorité des règles, ou encore les règles par défaut. Autant de curiosités qui ont souvent pour effet... des effets inattendus !

A cette problématique de fond, s'ajoute celle de la forme : comment nommer un paramètre ou une variable, sans parler des règles ?... Que des minuscules et un séparateur pour les noms composés, comme certains langages de scripts... Mais quel séparateur dans ce cas : un 'moins' ou un 'souligné' ?... Bon alors des majuscules, comme dans certains langages Objet... Dans ce cas on pourrait aussi utiliser le 'souligné', comme pour les attributs membres d'une classe...

Imaginons que l'on ait enfin réussi à statuer sur ces aspects liés à la casse, et après ?!... La règle qui permet d'afficher le titre, devra-t-elle s'appeler 'displayTitle' ou 'printTitle' ?... Mais est-ce qu'elle affiche, ou ne fait-elle que retourner une valeur ? Dans ce dernier cas, ça serait plutôt 'getTitle' !... Ou encore, pourquoi pas tout simplement 'title', histoire de mettre tout le monde d'accord... Peut être pour ne pas confondre avec les noms de variable ou de paramètre, ou encore la balise <title> elle même !

Vous ai-je convaincu de l'intérêt de règles de nommage ? Non ?!...

Et bien à cette différence avec l'extérieur (les autres langages), XSL ajoute une diversité interne !

Très (trop) nombreux sont les cas où l'on peut résoudre un même problème de différentes façons :

Je pense, et j'espère, vous avoir convaincus, si vous êtes sur un projet de plus... d'une personne (!), ou pire, un projet qui voit se succéder les développeurs au fil des mois, que la mise en place au moins de règles de nommage, au mieux de conventions de codage, et un investissement nécessaire... A vous de voir si vous préférez foncer tête baissée, et voir régner en despote bicéphale l'Anarchie et l'Aspirine, ou si vous préférez investir d'autant plus de temps que l'Harmonie et l'Homogénéité sont des valeurs importantes pour vous... Ouaouh, je viens d'inventer le paradigme 2A/2H ;o)

Acte II : Et moi qui ne voulais pas dupliquer.

XML rend possible la représentation de l'information dans un format universel, reconnu sur tous les systèmes, et adapté à une représentation sur le web.

En utilisant la technologie XSLT on peut extraire, trier et reformater ces informations XML et leur donner l'aspect adéquat pour les rendre accessibles à une application, quelle qu'elle soit.

Le couple XML/XSL, plutôt libertin, s'épanoui pleinement, à mon sens, dans la gestion :

Dans ces contextes, nous pouvons prendre le très bon exemple d'un document contenant l'ensemble des cas d'utilisation et scénarios spécifiant une application.

Tout d'abord, il est en effet plus simple de faire un "WinDiff" sur deux versions différentes d'un même document XML (quelques ko en mode texte) que sur son équivalent au format Word, à savoir un binaire de plusieurs Mo.

De plus, dans le cas d'une méthodologie dépassée, euh pardon, je voulais dire classique, après avoir généré à partir de ce document XML le dossier de spécification (on peut par exemple écrire un petit script, qui redescend la dernière version du gestionnaire de configuration avant de lui appliquer la feuille XSL), on peut s'atteler sereinement à la génération du dossier de tests, proche en contenu : juste besoin de faire une autre feuille XSL, sans dupliquer de contenu.

Il apparaît donc que XSL permet de résoudre une problématique courante : Comment éviter de dupliquer l'information brute, tout en respectant les représentations demandées, diverses et variées (en fonction des machines, des OS, des applications, des formats...).

Cependant, il faut être vigilant afin de ne pas repousser, reproduire, cette problématique au sein des traitements de cette information, à savoir la transformation XSL. En effet, lorsqu'un même fichier XML doit servir de source pour générer par exemple une page HTML et sa version imprimable, tout l'art réside dans le fait qu'une modification de la structure du XML d'entrée ne nécessite qu'une seule modification coté XSL, et non pas une pour la page HTML, et une pour sa version imprimable.

Dans tous les cas, la question de l'utilisation de XSL face à des traitements logiciels reste posée, et ouverte !

Acte III : Système de gestion de contenu ou de contenant ?

Pour vraiment conclure, si si, je vais rebondir sur deux choses.

Tout d'abord une présentation de Zope et Plone, faite en interne dans ma société. Cette présentation qui m'a vraiment séduite, présentait ce serveur d'application, et des plugins qui permettent d'en faire un CMS : un Système de Gestion de Contenu. Chaque ressource, chaque document est associé à un objet au sens Programmation Objet, et est en conséquence présenté à l'affichage sous forme d'une page web, dont l'apparence lui est propre. J'ai vraiment été emballé par la puissance de l'outil, qui permet d'intégrer des documents divers et variés en un gestionnaire unique, et d'y associer un workflow, une séquence de traitement, et un affichage qui lui sont particularisés selon plein de critères.

L'autre ressort, sera une citation qui à fait l'introduction du dossier "Le premier dictionnaire des technologies XML", paru dans le "01 Informatique" du 18/05/2004. Marie Varandat y expliquait :

"A trop se focaliser sur les architectures, on en a parfois oublié que ce n'est pas l'architecture qui structure la donnée, mais la donnée qui gouverne l'architecture. Car c'est d'elle que naît le potentiel évolutif de l'entreprise. Et c'est précisément là que XML joue un rôle majeur.

En structurant progressivement ce capital de l'entreprise - jusque-là inexploitable, car éparpillé dans différentes applications sans lien apparent –, il favorise une véritable gouvernance de la donnée, qui se concrétise par une optimisation des échanges internes et externes. Le système d'information n'est alors plus composé d'îlots régis par leurs propres règles. Il devient progressivement une formidable source d'information, dans laquelle l'entreprise peut piocher à volonté, sans être freinée par les formats et modèles propres à chacune de ses applications.".

Tout cela pour donc dire que, autant Zope et Plone peut s'avérer être une très bonne solution lorsque l'on doit intégrer des contenus aux formats diverses et variés, que l'on ne peut maîtriser. Mais au sein d'une société comme Pacte Novation (et Assigraph ;o), qu'est ce qui nous empêche de ne gérer en interne qu'un unique format de capitalisation ?...

Tant de par les besoins que nécessite notre communauté, que de par les compétences qu'elle possède, pourquoi ne pas écrire pour nos projets, dans des documents XML, les propositions techniques, les cahiers des charges, les dossiers de spécification et de tests, ou encore l'avancement du projet. Cet avancement pourrait contenir la description des tâches, réalisées et à venir, et donc le temps imputé par chaque développeur. Ainsi, en un clic on pourrait générer au format HTML, pour consultation, un état d'avancement à jour de ce projet à rebondissement qui dure depuis 2 ans, ou encore des bons de livraison détaillés, mais aussi les CRA, puis les CRAM, au format PDF, voire générer un fichier CSV pour mettre à jour directement le géstionnaire de projet centralisé de la société...

On pourrait également décrire en XML les descriptions des projets (une technique, plus courte, pour mettre à jour les CV par exemple, et une plus étoffée pour générer les fiches marketing), mais aussi divers guides (de programmation, du chef de projet...), des cours, voire les réunions techniques.

Ainsi, en un clic, on pourrait obtenir la dernière version du cours de programmation C#, ou encore une présentation HTML de la dernière réunion technique, directement sur le site de Pacte, ou la présentation au format PDF-Slide du projet phare d'il y a 3 ans, chacune en intégrant la dernière charte graphique de Pacte, bien que cette dernière ait été mise à jour la semaine dernière par le nouveau graphiste en inter-contrat.

Et puisque nous avons parlé de CV, soyons fou : contaminons les administratifs ! Il existe en effet une spécification XML orientée ressources humaines, qui inclue notamment la prise en charge des CV. Quel pactais n'a pas rêvé d'avoir à ajouter seulement 2 lignes de texte brut pour compléter son CV de son intervention sur son dernier projet (la description étant déjà faite), ce qui du coup, permettrait au commercial d'obtenir cette mise à jour dans le quart d'heure qui suit sa demande, afin qu'il puisse envoyer le CV dans l'après midi pour l'entretient du sur-lendemain.

Même la Direction Technique pourrait étoffer ce CV, à jour, des formations suivies par le développeur, et pouvoir ainsi juger, en regard du CV et des anciennes formations, de la pertinence de la dernière demande de formation du développeur.

HR-XML permet même de gérer le recrutement et l'organisation du personnel, la participation des prestataires d'assurance, la gestion des salaires ou encore les actions boursières...

Encore une fois, je n'envisage pas de fournir des documents XML bruts en guise de CV ou de dossier de spécifications, mais un document généré à la volé, forcément à jour, et au format qui convient. Je parle d'une véritable gestion de contenu, et pas de contenant !

En admettant que cela réponde à tous les besoins, du moins à une grande majorité, je suis persuadé que ça ne pourra pas se faire du jour au lendemain, et sans douleur, mais ce qui ne peux pas faire de mal, c'est de se poser la question...